package org.jvm.classfile.attributeinfo;

import org.jvm.classfile.*;

/**
 * 存储代码字节码、异常表等信息
 *
 * @author 海燕
 * @date 2023/1/8
 */
public class CodeAttribute implements AttributeInfo {

    /**
     * 操作数栈最大深度
     */
    private int maxStack;
    /**
     * 局部变量表大小
     */
    private int maxLocals;
    /**
     * 字节码
     */
    private byte[] code;
    /**
     * 异常处理表
     */
    private ExceptionTableEntry[] exceptionTable;
    /**
     * 附加的其他属性
     */
    private AttributeInfo[] attributes;

    private ConstantPool constantPool;

    public CodeAttribute(ConstantPool constantPool) {
        this.constantPool = constantPool;
    }

    @Override
    public void readInfo(ClassReader classReader, int attributeLength) {
        this.maxStack = classReader.readUint16();
        this.maxLocals = classReader.readUint16();
        int codeLength = classReader.readUint32();
        this.code = classReader.readBytes(codeLength);
        this.exceptionTable = readExceptionTable(classReader);
        this.attributes = AttributeInfoBuilder.newAttributeInfos(classReader, constantPool);
    }

    private ExceptionTableEntry[] readExceptionTable(ClassReader classReader) {
        int exceptionTableLength = classReader.readUint16();
        ExceptionTableEntry[] exceptionTable = new ExceptionTableEntry[exceptionTableLength];
        for (int i = 0; i < exceptionTableLength; i++) {
            int startPc = classReader.readUint16();
            int endPc = classReader.readUint16();
            int handlerPc = classReader.readUint16();
            int catchType = classReader.readUint16();
            exceptionTable[i] = new ExceptionTableEntry(startPc, endPc, handlerPc, catchType);
        }
        return exceptionTable;
    }

    public int getMaxStack() {
        return maxStack;
    }

    public int getMaxLocals() {
        return maxLocals;
    }

    public byte[] getCode() {
        return code;
    }

    public void setCode(byte[] code) {
        this.code = code;
    }

    public ExceptionTableEntry[] getExceptionTable() {
        return exceptionTable;
    }

    public void setExceptionTable(ExceptionTableEntry[] exceptionTable) {
        this.exceptionTable = exceptionTable;
    }

    public AttributeInfo[] getAttributes() {
        return attributes;
    }

    public void setAttributes(AttributeInfo[] attributes) {
        this.attributes = attributes;
    }

    public ConstantPool getConstantPool() {
        return constantPool;
    }

    public void setConstantPool(ConstantPool constantPool) {
        this.constantPool = constantPool;
    }
}
